#include "pch.h"
#include "dx.h"
#include <DirectXMath.h>
#include <DirectXColors.h>
#include <string>
#include <vector>

using namespace KennyKerr;
using namespace std;
using namespace DirectX;
#pragma warning(push)
#pragma warning(disable: 4838)
#pragma warning(disable: 4458)
#include <Model.h>
#pragma warning(pop)

using namespace KennyKerr;
using namespace std;
using namespace DirectX;

EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)

HWND g_hwnd;

// d3d related
Direct3D::Device           g_d3d;
Direct3D::DeviceContext    g_d3dc;
Direct3D::RenderTargetView g_rtView;
Direct3D::DepthStencilView g_dsView;
Dxgi::SwapChain1           g_swapChain;

LRESULT _stdcall WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
void Render();
void Draw();
void HandleResize();
void CreateDeviceResources();
void CreateDeviceSizeResources();

// wWinMain
int _stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
	WNDCLASSEX wcex = { sizeof(wcex) };
	wcex.hCursor       = LoadCursor(nullptr, IDC_ARROW);
	wcex.hIcon         = LoadIcon(nullptr, IDI_APPLICATION);
	wcex.lpszClassName = L"Simple Window";
	wcex.lpfnWndProc   = WndProc;
	RegisterClassEx(&wcex);

	g_hwnd = CreateWindowEx(0, 
							wcex.lpszClassName, 
							L"Simple Window", 
							WS_OVERLAPPEDWINDOW | WS_VISIBLE, 
							CW_USEDEFAULT, 
							CW_USEDEFAULT, 
							CW_USEDEFAULT, 
							CW_USEDEFAULT, 
							nullptr, 
							nullptr, 
							HINST_THISCOMPONENT, 
							nullptr);

	MSG msg{};
	while (msg.message != WM_QUIT)
	{
		while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		Render();
	}
}

// WndProc
LRESULT _stdcall WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	if (msg == WM_DESTROY)
	{
		PostQuitMessage(0);
	}
	else if (msg == WM_PAINT)
	{
		ValidateRect(hwnd, nullptr);
		Render();
		return 0;
	}
	else if (msg == WM_SIZE)
	{
		HandleResize();
	}
	return DefWindowProc(hwnd, msg, wparam, lparam);
}

// Render
void Render()
{
	if (!g_d3d)
	{
		g_d3d = Direct3D::CreateDevice();

		g_d3dc = g_d3d.GetImmediateContext();
		
		auto dxgi = g_d3d.GetDxgiFactory();
		g_swapChain = dxgi.CreateSwapChainForHwnd(g_d3d, g_hwnd);

		g_rtView = g_d3d.CreateRenderTargetView(g_swapChain);

		auto swapChainDesc = g_swapChain.GetDescription1();
		auto rtTexture = g_d3d.CreateTexture2D(Direct3D::TextureDescription2D{
			Dxgi::Format::D24_UNORM_S8_UINT,
			swapChainDesc.Width,
			swapChainDesc.Height,
			1U,
			1U,
			Direct3D::BindFlag::DepthStencil
		});
		g_dsView = g_d3d.CreateDepthStencilView(rtTexture, Direct3D::DepthStencilViewDescription{ Direct3D::DSVDimension::Texture2D });

		CreateDeviceResources();
		CreateDeviceSizeResources();
	}

	auto swapChainDesc = g_swapChain.GetDescription1();

	auto vp = Direct3D::ViewPort{ 0.0f, 0.0f, (float)swapChainDesc.Width, (float)swapChainDesc.Height };
	g_d3dc.RSSetViewports(1, &vp);

	g_d3dc.OMSetRenderTargets(1, &g_rtView, g_dsView);
	g_d3dc->ClearRenderTargetView(g_rtView.Get(), Colors::Blue);
	g_d3dc.ClearDepthStencilView(g_dsView);
	Draw();
	g_swapChain.Present();
}

// Handle resize
void HandleResize()
{
	if (g_d3d)
	{
		g_rtView.Reset();
		g_dsView.Reset();

		g_swapChain.ResizeBuffers();

		g_rtView = g_d3d.CreateRenderTargetView(g_swapChain);

		auto swapChainDesc = g_swapChain.GetDescription1();
		auto rtTexture = g_d3d.CreateTexture2D(Direct3D::TextureDescription2D{
			Dxgi::Format::D24_UNORM_S8_UINT,
			swapChainDesc.Width,
			swapChainDesc.Height,
			1U,
			1U,
			Direct3D::BindFlag::DepthStencil
		});
		g_dsView = g_d3d.CreateDepthStencilView(rtTexture, Direct3D::DepthStencilViewDescription{ Direct3D::DSVDimension::Texture2D });

		CreateDeviceSizeResources();
	}
}

// Create Device Resources
void CreateDeviceResources()
{
	 
}

// Create Device Size Resources
void CreateDeviceSizeResources()
{

}

// Draw
void Draw()
{

}